package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.dto.*;
import com.leyou.item.entity.Sku;
import com.leyou.item.entity.Spu;
import com.leyou.item.entity.SpuDetail;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**

 */
@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {

    @Autowired
    private BrandService brandService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private SpecGroupService specGroupService;

    @Autowired
    private SpecParamService specParamService;

    @Autowired
    private SpecDetailService specDetailService;

    @Autowired
    private SpuService spuService;

    @Autowired
    private SkuService skuService;

    @Autowired
    private SpuDetailService spuDetailService;

    @Override
    public PageDTO<SpuDTO> queryPage(Integer page, Integer rows, Long brandId, Long categoryId, Long id, Boolean saleable) {
        IPage<Spu> iPage = new Page<>(page, rows);

        page(iPage, new QueryWrapper<Spu>()
                .eq(brandId != null, "brand_id", brandId)
                .eq(categoryId != null, "cid3", categoryId)
                .eq(saleable != null, "saleable", saleable)
                .eq(id != null, "id", id)
        );


        List<SpuDTO> spuDTOS = SpuDTO.convertEntityList(iPage.getRecords());
        spuDTOS.forEach(spuDTO -> {
            //根据分类id的集合查询出对应的分类集合,并去除分类名称并拼接为字符串
            String names = this.categoryService
                    .queryCategoryByIds(spuDTO.getCategoryIds())
                    .stream()
                    .map(CategoryDTO::getName)
                    .collect(Collectors.joining("/"));
            spuDTO.setCategoryName(names);
            //根据brandId查询对应的品牌
            spuDTO.setBrandName(this.brandService.getById(spuDTO.getBrandId()).getName());
        });
        return new PageDTO<>(iPage.getTotal(), iPage.getPages(), spuDTOS);
    }


    @Override
    public List<SpecParamDTO> listSpec(Long id, Boolean searching) {
        //通过id获取到对应的规格参数,以及规格参数值,规格参数组

        //查询spu获取分类id
        Long cid = getById(id).getCid3();

        //用分类id查询当前分类下所有的规格参数
        List<SpecParamDTO> specParamDTOS = SpecParamDTO.
                convertEntityList(specParamService
                        .query()
                        .eq("category_id", cid)
                        .eq(null!=searching,"searching",searching)
                        .list());

        //获取规格参数的value
        SpuDetail spuDetail = this.specDetailService.getById(id);

        //nativeRead 的第一个参数,寄送   ,第二个参数,类型限定     作用是将json转为map
        //key规格参数的id,        value,规格参数的值
        Map<Long, Object> valueMap = JsonUtils.nativeRead(spuDetail.getSpecification(), new TypeReference<Map<Long, Object>>() {
        });

        //遍历specParamsDTO,给每个value赋值,每个value的值,就是valueMap的value
        specParamDTOS.forEach(specParamDTO -> {

            //规格参数的id
            Long key = specParamDTO.getId();

            specParamDTO.setValue(valueMap.get(key));
        });

        return specParamDTOS;
    }

    @Override
    public SpuDTO querySpuById(Long cid) {
        return new SpuDTO(spuService.getById(cid));
    }

    @Override
    @Transactional
    public void addGoods(SpuDTO spuDTO) {


        //健壮性
        if (CollectionUtils.isEmpty(spuDTO.getSkus())) {
            throw new LyException(400, "每个spu下至少要有一个sku");
        }
        //将DTO装换为实体类
        Spu spu = spuDTO.toEntity(Spu.class);
        //保存spu同时主键回显
        this.save(spu);


        SpuDetail detail = spuDTO.getSpuDetail().toEntity(SpuDetail.class);
        detail.setSpuId(spu.getId());

        this.specDetailService.save(detail);

//通过传参过来的spuDTO来获取Skus ,因为Sku至少有一个,有需要返回值,所以用stream流遍历转换为实体类,再赋值最后保存
        List<Sku> list = spuDTO.getSkus().stream()
                .map(skuDTO -> {
                    Sku sku = skuDTO.toEntity(Sku.class);
                    sku.setSpuId(spu.getId());
                    sku.setSaleable(true);
                    return sku;
                }).collect(Collectors.toList());

        this.skuService.saveBatch(list);
    }


    @Autowired
    private AmqpTemplate amqpTemplate;

    @Override
    @Transactional
    public void saleableById(Long cid, Boolean saleable) {
        //修改Spu表中的上下架状态以及更新时间
        Spu spu = new Spu();
        spu.setId(cid);
        spu.setSaleable(saleable);
        spu.setUpdateTime(new Date());
        //update tb_spu set saleable = false ,update_time = now() where id = #{id}
        this.updateById(spu);

        //修改Sku表中的上下架状态以及更新时间
        Sku sku = new Sku();
        sku.setSaleable(spu.getSaleable());
        sku.setUpdateTime(spu.getUpdateTime());
        //update tb_sku set saleable = false,update_time = now where spu_id = id
        //第一个参数:新的目标sku
        //第二个参数:查询条件
        this.skuService.update(sku, new QueryWrapper<Sku>().eq("spu_id", cid));

        //mq
        String routingKey = saleable ? "item.up" : "item.down";

        //向指定的交换机发送消息,消息内容为spuId
        this.amqpTemplate.convertAndSend("leyou.item",routingKey,cid);
    }

    @Override
    @Transactional
    public void updateGoods(SpuDTO spuDTO) {
        //修改spu
        //判断spu是否存在id,存在则需要修改,没有则不需要
        if (spuDTO.getId() != null) {
            //修改新增等和数据库有直接关系的都要转为实体类    entity
            Spu spu = spuDTO.toEntity(Spu.class);
            this.updateById(spu);
        }


        //修改spuDetail
        SpuDetailDTO spuDetailDTO = spuDTO.getSpuDetail();
        if (spuDetailDTO != null) {
            SpuDetail spuDetail = spuDetailDTO.toEntity(SpuDetail.class);
            this.specDetailService.updateById(spuDetail);
        }


        //修改sku
        List<SkuDTO> skuDTOS = spuDTO.getSkus();
        //如果skuDTOS为空,则不作操作,不为空则进行修改,删除或者新增
        if (!CollectionUtils.isEmpty(skuDTOS)) {
            List<Sku> skuList = skuDTOS.stream().map(skuDTO ->
                skuDTO.toEntity(Sku.class)
        ).collect(Collectors.toList());

            //map中最多两组，当key为true，表示saleable就是null，即表示不删除
            Map<Boolean, List<Sku>> skuMap = skuList
                    .stream()
                    .collect(Collectors.groupingBy(sku -> sku.getSaleable() == null));

            //获取要删除的sku集合
            List<Sku> skusToBeDelete = skuMap.get(false);
            //如果需要删除的集合不为空则需要删除对应的sku信息
            if (!CollectionUtils.isEmpty(skusToBeDelete)) {
                //根据sku的id集合删除对应的sku信息
                this.skuService.removeByIds(skusToBeDelete.stream().map(Sku::getId).collect(Collectors.toList()));
            }

            //获取需要添加或者修改的sku集合
            List<Sku> skusToBeAddOrUpdate = skuMap.get(true);
            if (!CollectionUtils.isEmpty(skusToBeAddOrUpdate)) {
                //批量修改或新增
                this.skuService.saveOrUpdateBatch(skusToBeAddOrUpdate);
            }
        }

    }

    @Override
    public SpuDTO queryGoods(Long spuId) {
        List<SpuDTO> spuDTOS = this.queryPage(1, 1,null,null,spuId,null).getItems();
        if (CollectionUtils.isEmpty(spuDTOS)) {
            throw new LyException(204, "对应商品不存在");
        }
        SpuDTO spuDTO = spuDTOS.get(0);
        spuDTO.setSkus(this.skuService.querySkuListBySpuId(spuId));
        spuDTO.setSpuDetail(this.spuDetailService.queryDetailById(spuId));
        return spuDTO;
    }


}
